﻿using System;
using System.Collections;
using System.Collections.Generic;
using TrueSync;

public enum SkillStreamHeightTypeEnum
{
    OnGround,
    InAir,
}

[System.Serializable]
public class SkillStreamState : StateBase
{
    //所属技能ID
    public int SkillGroupID;
    //技能流ID
    public int ID;
    //技能流描述
    public string SkillStreamDescription;
    //高度设定
    public SkillStreamHeightTypeEnum SkillStreamHeightType;

    //特性标记
    //首技能流标记
    public bool IsFirstSkillStreamInSkill;
    //跳转技能流
    public bool IsPredictSkillStream;
    public bool CanMoveInSkillStream;
    //技能中移动速度
    public FP MoveSpeedInSkillStream;
    //技能可蓄力配置
    public bool CanChargeAttack;
    public List<int> ChargeAttackCallbackEventID;
    public int MaxChargeAttackFrames;

    //终端标记
    //技能中断移动
    public bool SkillStreamStopMove;
    //收到激励中断技能流
    public bool SkillStreamBreakByStimulate;
    //允许超必杀技打断
    public bool AllowSuperKillSkillBreak;
    //允许必杀技打断
    public bool AllowKillSkillBreak;
    //允许特殊及打断
    public bool AllowSpecialSkillBreak;
    //允许制定技能打断
    public List<int> AllowSkillBreakIDs;
    public int DefaultNextSkillStreamID;//后继技能流ID, -1表示没有后继了
    public FP EnergyConsumptionPercent;//能量消耗
    //总时间
    public int SkillStreamTotalTime;
    //事件组ID
    public List<int> EventIDArray;

    LogicInputComponent mInputComponent;
    LogicMoveComponent mMoveComponent;

    public override StateEnum StateName
    {
        get
        {
            return StateEnum.SkillStream;
        }
    }

    public override void Enter(LogicEntity lEntity, StateBase lastState, object[] stateParams)
    {
        base.Enter(lEntity, lastState, stateParams);

        if(SkillStreamStopMove)
        {
            LogicMoveComponent moveComponent = mLEntity.GetLogicComponent<LogicMoveComponent>();
            moveComponent.MoveSpeed = TSVector2.zero;
        }

        LogicSkillGroupComponent skillGroupComponent = mLEntity.GetLogicComponent<LogicSkillGroupComponent>();
        if(skillGroupComponent.CurrentSkillGroup.DetectEnergyConsumption && skillGroupComponent.CurrentSkillGroup.EnergyConsumption > 0 && EnergyConsumptionPercent > 0)
        {
            LogicStatusComponent statusComponent = mLEntity.GetLogicComponent<LogicStatusComponent>();
            statusComponent.UseEnergy((skillGroupComponent.CurrentSkillGroup.EnergyConsumption * EnergyConsumptionPercent).AsInt());
        }

        LogicEventComponent eventComponent = mLEntity.GetLogicComponent<LogicEventComponent>();
        eventComponent.SetEvent(EventIDArray);

        mInputComponent = lEntity.GetLogicComponent<LogicInputComponent>();
        mMoveComponent = lEntity.GetLogicComponent<LogicMoveComponent>();

    }

    public void Predict(LogicEntity lEntity, object[] stateParams)
    {
        mLEntity = lEntity;
        LogicEventComponent eventComponent = mLEntity.GetLogicComponent<LogicEventComponent>();
        eventComponent.SetEvent(EventIDArray);
    }

    public override void Excute(FP deltaTime)
    {
        if(IsFinished())
        {
            LogicSkillGroupComponent skillGroupComponent = mLEntity.GetLogicComponent<LogicSkillGroupComponent>();
            if (DefaultNextSkillStreamID == -1)
            {
                mLEntity.GetLogicComponent<LogicStateMachineComponent>().ChangeState(StateEnum.Stand);
            }
            else
            {
                SkillStreamState skillStream = skillGroupComponent.GetSkillStream(DefaultNextSkillStreamID);
                mLEntity.GetLogicComponent<LogicStateMachineComponent>().ChangeToSkillStream(skillStream);
            }
        }

        //if(CanChargeAttack && !mChargeAttackFired && (mReleasedSkillBtn || IsFinished()))
        //{
        //    mChargeAttackFired = true;

        //    LogicEventComponent eventComponent = mLEntity.GetLogicComponent<LogicEventComponent>();
        //    for(int i = 0; i < ChargeAttackCallbackEventID.Count; i++)
        //    {
        //        eventComponent.CallEvent(ChargeAttackCallbackEventID[i]);//TODO:蓄力时间
        //    }
        //}

    }

    public override void Exit()
    {
        LogicEventComponent eventComponent = mLEntity.GetLogicComponent<LogicEventComponent>();
        eventComponent.DestroyEvent(EventIDArray);
        mInputComponent = null;
        mMoveComponent = null;
        base.Exit();
    }

    public override void OnInputDirection(int direction)
    {
        LogicMoveComponent moveComponent = mLEntity.GetLogicComponent<LogicMoveComponent>();
        switch(direction)
        {
            case 1:
            case 4:
            case 7:
                moveComponent.MoveSpeed = new TSVector2(-moveComponent.FaceDirection * MoveSpeedInSkillStream, 0);
                break;
            case 3:
            case 6:
            case 9:
                moveComponent.MoveSpeed = new TSVector2(moveComponent.FaceDirection * MoveSpeedInSkillStream, 0);
                break;
            case 5:
                moveComponent.MoveSpeed = TSVector2.zero; 
                break;

        }
    }

    public override void OnStimulate(Stimulate stimulate)
    {
        if (SkillStreamBreakByStimulate == false)
            return;

        LogicStateMachineComponent stateMachineComponent = mLEntity.GetLogicComponent<LogicStateMachineComponent>();
        if(SkillStreamHeightType == SkillStreamHeightTypeEnum.OnGround)
        {
            switch (stimulate.StimulateType)
            {
                case StimulateTypeEnum.FalldownStimulate:
                    stateMachineComponent.ChangeState(StateEnum.KnockdownHit);
                    break;
                case StimulateTypeEnum.HitFloatStimulate:
                    HitFloatStimulate hitfloatStimulate = (HitFloatStimulate)stimulate;
                    stateMachineComponent.ChangeState(StateEnum.FloatHit, hitfloatStimulate.XMoveLength, hitfloatStimulate.XMoveSpeed, hitfloatStimulate.YHeight);
                    break;
                case StimulateTypeEnum.HitBackStimulate:
                    HitBackStimulate hitbackStimulate = (HitBackStimulate)stimulate;
                    stateMachineComponent.ChangeState(StateEnum.StandHit, hitbackStimulate.XMoveLength, hitbackStimulate.XMoveSpeed);
                    break;
                case StimulateTypeEnum.HitFlyStimulate:
                    HitFlyStimulate hitflyStimulate = (HitFlyStimulate)stimulate;
                    stateMachineComponent.ChangeState(StateEnum.HitFly, hitflyStimulate.XMoveLength, hitflyStimulate.XMoveSpeed);
                    break;
                case StimulateTypeEnum.ThrowStimulate:
                    stateMachineComponent.ChangeState(StateEnum.ThrowHit);
                    break;
                case StimulateTypeEnum.BeCounterAttackStimulate:
                    stateMachineComponent.ChangeState(StateEnum.CounterAttackHit);
                    break;
            }
        }
        else if(SkillStreamHeightType == SkillStreamHeightTypeEnum.InAir)
        {
            switch (stimulate.StimulateType)
            {
                case StimulateTypeEnum.HitFloatStimulate:
                    HitFloatStimulate hitfloatStimulate = (HitFloatStimulate)stimulate;
                    stateMachineComponent.ChangeState(StateEnum.FloatHit, hitfloatStimulate.XMoveLength, hitfloatStimulate.XMoveSpeed, hitfloatStimulate.YHeight); 
                    break;
                case StimulateTypeEnum.FalldownStimulate:
                case StimulateTypeEnum.HitBackStimulate:
                case StimulateTypeEnum.HitFlyStimulate:
                    stateMachineComponent.ChangeState(StateEnum.JumpHit);
                    break;
                case StimulateTypeEnum.ThrowStimulate:
                    stateMachineComponent.ChangeState(StateEnum.ThrowHit);
                    break;
            }
        }
    }

    public override void Serialize(EByte ms)
    {
        base.Serialize(ms);
        ms.WriteInt(SkillGroupID);
        ms.WriteInt(ID);
        ms.WriteString(SkillStreamDescription);
        ms.WriteInt((int)SkillStreamHeightType);
        ms.WriteInt(IsFirstSkillStreamInSkill ? 1 : 0);
        ms.WriteInt(IsPredictSkillStream ? 1 : 0);
        ms.WriteInt(CanMoveInSkillStream ? 1 : 0);
        ms.WriteLong(MoveSpeedInSkillStream.RawValue);
        ms.WriteInt(CanChargeAttack ? 1 : 0);
        ms.WriteInt(ChargeAttackCallbackEventID.Count);
        for(int i = 0; i < ChargeAttackCallbackEventID.Count; i++)
        {
            ms.WriteInt(ChargeAttackCallbackEventID[i]);
        }
        ms.WriteInt(MaxChargeAttackFrames);
        ms.WriteInt(SkillStreamStopMove ? 1 : 0);
        ms.WriteInt(SkillStreamBreakByStimulate ? 1 : 0);
        ms.WriteInt(AllowSuperKillSkillBreak ? 1 : 0);
        ms.WriteInt(AllowKillSkillBreak ? 1 : 0);
        ms.WriteInt(AllowSpecialSkillBreak ? 1 : 0);
        ms.WriteInt(AllowSkillBreakIDs.Count);
        for(int i = 0; i < AllowSkillBreakIDs.Count; i++)
        {
            ms.WriteInt(AllowSkillBreakIDs[i]);
        }
        ms.WriteInt(DefaultNextSkillStreamID);
        ms.WriteLong(EnergyConsumptionPercent.RawValue);
    }

    public override void Deserialize(EByte ms)
    {
        base.Deserialize(ms);
        SkillGroupID = ms.ReadInt();
        ID = ms.ReadInt();
        SkillStreamDescription = ms.ReadString();
        SkillStreamHeightType = (SkillStreamHeightTypeEnum)ms.ReadInt();
        IsFirstSkillStreamInSkill = ms.ReadInt() == 1;
        IsPredictSkillStream = ms.ReadInt() == 1;
        CanMoveInSkillStream = ms.ReadInt() == 1;
        MoveSpeedInSkillStream = FP.FromRaw(ms.ReadLong());
        CanChargeAttack = ms.ReadInt() == 1;
        int chargetAttackCallbackEventIDNum = ms.ReadInt();
        ChargeAttackCallbackEventID = new List<int>(chargetAttackCallbackEventIDNum);
        for(int i = 0; i < chargetAttackCallbackEventIDNum; i++)
        {
            ChargeAttackCallbackEventID[i] = ms.ReadInt();
        }
        MaxChargeAttackFrames = ms.ReadInt();
        SkillStreamStopMove = ms.ReadInt() == 1;
        SkillStreamBreakByStimulate = ms.ReadInt() == 1;
        AllowSuperKillSkillBreak = ms.ReadInt() == 1;
        AllowKillSkillBreak = ms.ReadInt() == 1;
        AllowSpecialSkillBreak = ms.ReadInt() == 1;
        int allowSkillBreakIDNum = ms.ReadInt();
        AllowSkillBreakIDs = new List<int>(allowSkillBreakIDNum);
        for(int i = 0; i < allowSkillBreakIDNum; i++)
        {
            AllowSkillBreakIDs[i] = ms.ReadInt();
        }
        DefaultNextSkillStreamID = ms.ReadInt();
        EnergyConsumptionPercent = FP.FromRaw(ms.ReadLong());
    }

}
